﻿/*
 *********************************************************************
 *    Management Extensions for Windows Windows Server AppFabric     *
 *********************************************************************
 *    Author    : Fatih Boy [fatih@enterprisecoding.com]             *
 *    Web site  : http://www.enterprisecoding.com                    *
 *********************************************************************
 *    License   : GNU Library General Public License (LGPL)          * 
 *********************************************************************
 */

using System;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Threading;

namespace Com.Enterprisecoding.AppFabric.Extensions.Powershell {
    internal class PowershellHost : IDisposable {
        #region Data Members
        private volatile PowerShell powershell = PowerShell.Create();
        private static ExtensionsHost host;
        private static volatile ExtensionsRunspacePool runspacePool;
        private static AutoResetEvent runspaceAvailableEvent = new AutoResetEvent(false);
        private static object lockObject = new object();
        #endregion

        #region Properties
        private static ExtensionsHost Host {
            get {
                if (host == null) {
                    host = new ExtensionsHost();
                }

                return host;
            }
        }

        private static ExtensionsRunspacePool RunspacePool {
            get {
                if (runspacePool == null) {
                    lock (lockObject) {
                        if (runspacePool == null) {
                            var sessionState = InitialSessionState.CreateDefault();
                            sessionState.LanguageMode = PSLanguageMode.FullLanguage;
                            sessionState.ImportPSModule(new[] { "DistributedCacheAdministration" });

                            runspacePool = new ExtensionsRunspacePool(Host, sessionState);
                            runspacePool.RunspaceAvailable += RunspaceAvailable;
                            runspacePool.CreateRunspaceAsync();
                        }
                    }
                }

                return runspacePool;
            }
        }
        #endregion

        private static void RunspaceAvailable(object sender, EventArgs e) {
            runspaceAvailableEvent.Set();
        }

        public PSDataCollection<PSObject> Invoke() {
            Runspace runspace = null;
            try {
                var invocationResults = new PSDataCollection<PSObject>();
                var invocationSettings = new PSInvocationSettings { Host = PowershellHost.Host };

                runspaceAvailableEvent.WaitOne(1000, false); //wait for runspace initialization
                runspace = RunspacePool.GetRunspace();
                powershell.Runspace = runspace;
                
                powershell.Invoke<PSObject>(null, invocationResults, invocationSettings);

                return invocationResults;
            }
            catch (Exception) {
                throw;
            }
            finally {
                if (runspace!=null) {
                    runspacePool.ReleaseRunspace(runspace);
                }
            }
        }

        public void AddCommand(string command) {
            powershell.Commands.AddCommand(command);
        }
        public void AddParameter(string parameterName) {
            powershell.Commands.AddParameter(parameterName);
        }
        public void AddParameter(string parameterName, object value) {
            powershell.Commands.AddParameter(parameterName, value);
        }

        #region IDisposable Members

        public void Dispose() {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing) {
            if (disposing) {
                if (powershell != null) {
                    powershell.Dispose();
                    powershell = null;
                }
            }
        }
        #endregion
    }
}